import { ComponentFactoryResolver, Injectable, Injector } from '@angular/core';
import { MessagerService } from '@farris/ui-messager';
import { BsModalService } from '@farris/ui-modal';
import { NotifyService } from '@farris/ui-notify';
import { UpdateSchemaComponent } from './update-schema.component';
import { LoadingService } from '@farris/ui-loading';
import { FormBasicService, FormSchema, FormSchemaEntity, FormSchemaEntityField, DomService, SchemaService } from '@farris/designer-services';
import { Observable } from 'rxjs';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { IRefreshAfterChangedService } from './refresh.service';

export class UpdateFormSchemaService {

  private notifyService: NotifyService;
  private domService: DomService;
  private schemaService: SchemaService;
  private msgService: MessagerService;
  private resolver: ComponentFactoryResolver;
  private modalService: BsModalService;
  private http: HttpClient;
  private formBasicService: FormBasicService;
  private loadingService: LoadingService;


  private refreshAfterChangedServ: IRefreshAfterChangedService;

  constructor(private injector: Injector) {

    this.notifyService = this.injector.get(NotifyService);
    this.domService = this.injector.get(DomService);
    this.schemaService = this.injector.get(SchemaService);
    this.msgService = this.injector.get(MessagerService);
    this.resolver = this.injector.get(ComponentFactoryResolver);
    this.modalService = this.injector.get(BsModalService);
    this.http = this.injector.get(HttpClient);
    this.formBasicService = this.injector.get(FormBasicService);
    this.loadingService = this.injector.get(LoadingService);
  }


  /**
   * 同步VO-> schema
   */
  synchronizeVO(refreshAfterChangedServ: IRefreshAfterChangedService) {
    this.refreshAfterChangedServ = refreshAfterChangedServ;

    const schema = this.domService.getSchemas();
    if (!schema || !schema.id) {
      this.notifyService.error('VO 标识不存在，请检查表单DOM结构');
      return;
    }
    const loading = this.loadingService.show({ container: 'body', message: '请稍候...' });

    const qdpInfo = this.domService.getQDPInfo();
    if (qdpInfo) {
      const formInfo = {
        qoMetadataId: qdpInfo.qoMetadata[0].id,
        packgetName: qdpInfo.packgetName,
        voCode: schema.code,
        relativePath: this.formBasicService.formMetaBasicInfo.relativePath,
        nameSpace: this.formBasicService.formMetaBasicInfo.nameSpace
      };
      this.createVMFromQO(formInfo).subscribe(voMetadata => {
        if (voMetadata) {
          this.converVO2Schema(schema, loading);
        }
      }, error => {
        loading.close();
        this.notifyService.error('更新失败');
      });
    } else {
      this.converVO2Schema(schema, loading);
    }
  }

  private converVO2Schema(schema: any, loading: any) {
    const sessionId = '';
    this.schemaService.converVO2Schema(schema.id, sessionId).subscribe(data => {
      this.checkAndUppdateSchema(schema, data, loading);
    }, error => {
      loading.close();
      this.notifyService.error('更新失败');
    });
  }

  /**
   * 更新Schema节点
   */
  private _updateSchemaEntities(oldSchema: FormSchema, newSchema: FormSchema, loading) {
    // 旧表单升级：解决id与originalId不匹配的问题
    const updateVersion = this.domService.getUpdateVersion();
    if (updateVersion && updateVersion <= '190103' && this._checkIsNeedUpdateId(oldSchema.entities)) {
      oldSchema.entities = this._updateOldFormId(oldSchema.entities, newSchema.entities);
    }

    loading.close();

    const compFactory = this.resolver.resolveComponentFactory(UpdateSchemaComponent);
    const compRef = compFactory.create(this.injector);
    compRef.instance.oldSchema = oldSchema;
    compRef.instance.newSchema = newSchema;

    compRef.instance.refreshAfterChangedServ = this.refreshAfterChangedServ;

    const modalConfig = {
      title: '更新表单schema',
      width: 950,
      height: 560,
      resizable: false,
      buttons: compRef.instance.btns
    };


    const modal = this.modalService.show(compRef, modalConfig);
    compRef.instance.closeModal.subscribe(() => {
      modal.close();
    });
  }
  /**
   * 判断主对象ID是否变更
   */
  private _checkMainEntitiyID(oldSchemaEntities: FormSchemaEntity[], newSchemaEntities: FormSchemaEntity[]) {
    const mainEntity = oldSchemaEntities[0];
    const oldMainEntityID = mainEntity.id;
    const newMainEntityID = newSchemaEntities[0].id;
    return oldMainEntityID === newMainEntityID;

  }
  /**
   * 校验并更新Schema
   */
  private checkAndUppdateSchema(oldSchema: FormSchema, newSchema: FormSchema, loading: any) {
    if (!newSchema) {
      loading.close();
      this.notifyService.error('更新失败');
      return;
    }

    if (!this._checkMainEntitiyID(oldSchema.entities, newSchema.entities)) {
      loading.close();
      this.msgService.question('VO主对象ID已更改，更新表单schema后需要重新添加控件，确定更新？', () => {
        // 场景①：表单主对象ID已更改，但用户选择更新
        this._updateSchemaEntities(oldSchema, newSchema, loading);
      }, () => {
        // 场景②：表单主对象ID已更改，但用户选择不更新
        return;
      });
    } else {
      // 场景③：表单主对象ID未更改，表单升级后更新schema节点
      this._updateSchemaEntities(oldSchema, newSchema, loading);
    }

  }

  /**
   * 旧表单升级：解决id与originalId不匹配的问题
   */
  private _updateOldFormId(oldSchemaEntities: FormSchemaEntity[], newSchemaEntities: FormSchemaEntity[]): FormSchemaEntity[] {
    // console.log('旧表单升级：解决id与originalId不匹配的问题');
    const dom = this.domService.getDomJson();
    let domStr = JSON.stringify(dom);

    domStr = this.recursiveSchema(oldSchemaEntities, newSchemaEntities, domStr);
    // this.domJson = JSON.parse(domStr);
    this.domService.setDomJson(JSON.parse(domStr));

    const schema = this.domService.getSchemas();
    return schema.entities;
  }

  /**
   * 旧表单升级：判断主表的主键字段id和originalId是否相等 => 判断表单是否需要更新
   */
  private _checkIsNeedUpdateId(oldSchemaEntities: FormSchemaEntity[]): boolean {
    if (!oldSchemaEntities || oldSchemaEntities.length === 0) {
      return;
    }
    const mainEntity = oldSchemaEntities[0];
    const primaryLabel = mainEntity.type.primary;
    const fields = mainEntity.type.fields;
    const primaryField = fields.find(f => f.label === primaryLabel);
    if (primaryField && primaryField.id === primaryField.originalId) {
      return false;
    }
    return true;
  }

  /**
   * 旧表单升级：遍历schema实体，原表单中所有的id全量替换为新schema字段的id
   */
  private recursiveSchema(oldSchemaEntities: FormSchemaEntity[], newSchemaEntities: FormSchemaEntity[], domStr: string): string {
    if (!oldSchemaEntities || oldSchemaEntities.length === 0 || !newSchemaEntities || newSchemaEntities.length === 0) {
      return;
    }
    oldSchemaEntities.forEach(entity => {
      const entityId = entity.id;
      const newEntity = newSchemaEntities.find(e => e.id === entityId);
      if (!newEntity) {
        return;
      }
      entity.type.fields.forEach(field => {
        const newField = newEntity.type.fields.find(f => f.originalId === field.originalId);
        domStr = this._recursiveField(field, newField, domStr);
      });

      if (entity.type.entities && entity.type.entities.length > 0) {
        domStr = this.recursiveSchema(entity.type.entities, newEntity.type.entities, domStr);
      }
    });

    return domStr;
  }

  /**
   * 旧表单升级：遍历schema字段
   */
  private _recursiveField(oldField: FormSchemaEntityField, newField, domStr: string): string {
    if (!oldField || !newField) {
      return domStr;
    }
    if (oldField.$type === 'SimpleField') {

      // 简单字段：原表单中所有的id全量替换为新schema字段的id
      const regExp = new RegExp(oldField.id, 'g');
      domStr = domStr.replace(regExp, newField.id);
    } else if (oldField.type.fields && oldField.type.fields.length > 0) {
      // 复杂字段
      oldField.type.fields.forEach(f => {
        const childField = newField.type.fields.find(n => n.originalId === f.originalId);
        domStr = this._recursiveField(f, childField, domStr);
      });
    }

    return domStr;
  }

  /**
   * 调用QO生成VO
   */
  private createVMFromQO(formInfo: any): Observable<any> {
    const url = '/api/dev/main/v1.0/qometadata/generatevmfromqo';
    return this.http.put(
      url,
      {
        qoid: formInfo.qoMetadataId
        , comcmppkgname: 'Inspur.GS.Gsp.QDP.QdpCommonCmp'
        , qopkgname: formInfo.packgetName
        , formcode: formInfo.voCode
        , formpath: formInfo.relativePath
        , nameSpace: formInfo.nameSpace
      },
      {
        headers: new HttpHeaders({ SessionId: '' }), responseType: 'json'
      }
    );
  }
}
